// 2025/4/7: 首个版本
// 2025/4/9: 修正了道路名称的存储方式
// 2025/6/12: 协议名常量改为public
// 2025/7/21: 修正speedLimit插值

package com.appox.samples;

import com.appox.Sample;
import com.appox.GeneralSample;
import com.appox.GeneralElement;
import java.util.ArrayList;
import java.util.List;

/**
 * 环境样本数据类
 */
public class EnvSample extends Sample {

    /**
     * 天气类型
     */
    public enum WeatherType {
        UNKNOWN(0), // 未知
        SUNNY(1),   // 晴
        CLOUDY(2),  // 阴
        RAINY(3),   // 雨
        SNOWY(4),   // 雪
        FOGGY(5),   // 雾
        SAND(6);    // 沙尘
        
        private final int value;
        
        WeatherType(int value) {
            this.value = value;
        }
        
        public int getValue() {
            return value;
        }
        
        public static WeatherType fromValue(int value) {
            for (WeatherType type : WeatherType.values()) {
                if (type.getValue() == value) {
                    return type;
                }
            }
            return UNKNOWN;
        }
    }

    /**
     * 道路类型
     */
    public enum RoadType {
        UNKNOWN(0),     // 未知
        HIGHWAY(1),     // Without traffic light / 高速路，无红绿灯
        CITY_EXPRESS(2),// Without traffic light / 城市快速路，无红绿灯
        CITY_MAIN(3),   // With traffic light / 城市主干道，有红绿灯
        GENERAL_ROAD(4),// With traffic light / 一般道路，有红绿灯
        COUNTRY_ROAD(5);// Without traffic light / 乡村道路，无红绿灯
        
        private final int value;
        
        RoadType(int value) {
            this.value = value;
        }
        
        public int getValue() {
            return value;
        }
        
        public static RoadType fromValue(int value) {
            for (RoadType type : RoadType.values()) {
                if (type.getValue() == value) {
                    return type;
                }
            }
            return UNKNOWN;
        }
    }

    /**
     * 场所类型
     */
    public enum SpotType {
        UNKNOWN(0),         // 未知
        TOLL_GATE(1),       // 收费站
        SERVICE_AREA(2),    // 服务区
        TUNNEL(3),          // 隧道
        ACCIDENT(4),        // 事故
        CROSSING(5),        // Intersection / 路口
        ROUNDABOUT(7),      // 环岛
        HIGHWAY_ENTRANCE(8),// 高速入口
        HIGHWAY_EXIT(9),    // 高速出口
        BRIDGE(10),         // 桥
        EXPRESS_ENTRANCE(11), // 快速路入口
        EXPRESS_EXIT(12);   // 快速路出口
        
        private final int value;
        
        SpotType(int value) {
            this.value = value;
        }
        
        public int getValue() {
            return value;
        }
        
        public static SpotType fromValue(int value) {
            for (SpotType type : SpotType.values()) {
                if (type.getValue() == value) {
                    return type;
                }
            }
            return UNKNOWN;
        }
    }

    /**
     * 场所信息
     */
    public static class Spot {
        private SpotType type;    // 场所类型
        private double distance;  // [m] 本车到场所的距离

        public Spot() {
            this.type = SpotType.UNKNOWN;
            this.distance = 0;
        }

        public Spot(SpotType type, double distance) {
            this.type = type;
            this.distance = distance;
        }

        public SpotType getType() {
            return type;
        }

        public void setType(SpotType type) {
            this.type = type;
        }

        public double getDistance() {
            return distance;
        }

        public void setDistance(double distance) {
            this.distance = distance;
        }
    }

    /**
     * 交通状况
     */
    public enum TrafficStatus {
        UNKNOWN(0), // 未知
        OPEN(1),    // 畅通
        SLOW(2),    // 缓慢
        CROWDED(3), // 拥挤
        REVERSE(4); // Only for adjacent lane traffic / 逆向（仅限相邻车道交通状况）
        
        private final int value;
        
        TrafficStatus(int value) {
            this.value = value;
        }
        
        public int getValue() {
            return value;
        }
        
        public static TrafficStatus fromValue(int value) {
            for (TrafficStatus status : TrafficStatus.values()) {
                if (status.getValue() == value) {
                    return status;
                }
            }
            return UNKNOWN;
        }
    }

    /**
     * 风向
     */
    public enum WindDirection {
        UNKNOWN(0),    // 未知
        EAST(1),       // 东风
        SOUTH(2),      // 南风
        WEST(3),       // 西风
        NORTH(4),      // 北风
        SOUTH_EAST(5), // 东南风
        NORTH_EAST(6), // 东北风
        SOUTH_WEST(7), // 西南风
        NORTH_WEST(8); // 西北风
        
        private final int value;
        
        WindDirection(int value) {
            this.value = value;
        }
        
        public int getValue() {
            return value;
        }
        
        public static WindDirection fromValue(int value) {
            for (WindDirection direction : WindDirection.values()) {
                if (direction.getValue() == value) {
                    return direction;
                }
            }
            return UNKNOWN;
        }
    }

    /**
     * 路面状况
     */
    public enum RoadSurfaceStatus {
        UNKNOWN(0),      // 未知
        DRY(1),          // 干燥
        WET(2),          // 湿滑
        SNOW_COVERED(3), // 积雪
        FROZEN(4);       // 结冰
        
        private final int value;
        
        RoadSurfaceStatus(int value) {
            this.value = value;
        }
        
        public int getValue() {
            return value;
        }
        
        public static RoadSurfaceStatus fromValue(int value) {
            for (RoadSurfaceStatus status : RoadSurfaceStatus.values()) {
                if (status.getValue() == value) {
                    return status;
                }
            }
            return UNKNOWN;
        }
    }

    /**
     * 灾害状况
     */
    public enum DisasterStatus {
        UNKNOWN(0), // 未知
        NO(1),      // 无灾害
        YES(2);     // 有灾害
        
        private final int value;
        
        DisasterStatus(int value) {
            this.value = value;
        }
        
        public int getValue() {
            return value;
        }
        
        public static DisasterStatus fromValue(int value) {
            for (DisasterStatus status : DisasterStatus.values()) {
                if (status.getValue() == value) {
                    return status;
                }
            }
            return UNKNOWN;
        }
    }

    // 基本属性
    private WeatherType weatherType;        // 天气类型
    private Double temperature;             // [°C] 温度
    private Double humidity;                // [%] 相对湿度
    private Double pressure;                // [mb] 气压
    private Double pm25;                    // [ug/m3] PM 2.5
    private Double pm10;                    // [ug/m3] PM 10
    private Double o3Concentration;         // [ppb] 臭氧浓度
    private Double coConcentration;         // [ppb] 一氧化碳浓度
    private Double so2Concentration;        // [ppb] 二氧化硫浓度
    private Double no2Concentration;        // [ppb] 二氧化氮浓度
    private Double visibility;              // [KM] 能见度
    private Double illumination;            // [lux] 光照强度
    private Double totalRadiationIntensity; // [W/m2] 总辐射强度
    private Double uvRadiationIntensity;    // [W/m2] 紫外线辐射强度
    private Double rainfall;                // [mm/min] 瞬时雨量
    private Double cumulativeRainfall;      // [mm] 累计雨量
    private Double windSpeed;               // [m/s] 风速
    private Double accurateWindDirection;   // [deg] 精确风向，北风为0，CCW为正，范围在-180～180度
    private WindDirection windDirection;    // 大致风向
    private DisasterStatus typhoonStatus;   // 台风状况
    private DisasterStatus tornadoStatus;   // 龙卷风状况
    private DisasterStatus lightningStatus; // 雷电状况
    private DisasterStatus hailStatus;      // 冰雹状况
    private String roadName;                // 道路名称
    private Integer speedLimit;             // [KPH] 道路限速
    private RoadType roadType;              // 道路类型
    private RoadSurfaceStatus roadSurfaceStatus; // 路面状况
    private TrafficStatus roadTraffic;      // 道路交通状况
    private TrafficStatus currentLaneTraffic; // 本车道交通状况
    private TrafficStatus leftLaneTraffic;  // 左车道交通状况
    private TrafficStatus rightLaneTraffic; // 右车道交通状况
    private List<Spot> spots;               // 场所列表

    /**
     * 构造函数，初始化默认值
     */
    public EnvSample() {
        // 设置默认值
        this.weatherType = WeatherType.UNKNOWN;
        this.windDirection = WindDirection.UNKNOWN;
        this.roadType = RoadType.UNKNOWN;
        this.roadSurfaceStatus = RoadSurfaceStatus.UNKNOWN;
        this.roadTraffic = TrafficStatus.UNKNOWN;
        this.currentLaneTraffic = TrafficStatus.UNKNOWN;
        this.leftLaneTraffic = TrafficStatus.UNKNOWN;
        this.rightLaneTraffic = TrafficStatus.UNKNOWN;
        this.typhoonStatus = DisasterStatus.UNKNOWN;
        this.tornadoStatus = DisasterStatus.UNKNOWN;
        this.lightningStatus = DisasterStatus.UNKNOWN;
        this.hailStatus = DisasterStatus.UNKNOWN;
        this.spots = new ArrayList<>();
    }

    // 所有属性的getter和setter方法
    public WeatherType getWeatherType() {
        return weatherType;
    }

    public void setWeatherType(WeatherType weatherType) {
        this.weatherType = weatherType;
    }

    public Double getTemperature() {
        return temperature;
    }

    public void setTemperature(Double temperature) {
        this.temperature = temperature;
    }

    public Double getHumidity() {
        return humidity;
    }

    public void setHumidity(Double humidity) {
        this.humidity = humidity;
    }

    public Double getPressure() {
        return pressure;
    }

    public void setPressure(Double pressure) {
        this.pressure = pressure;
    }

    public Double getPm25() {
        return pm25;
    }

    public void setPm25(Double pm25) {
        this.pm25 = pm25;
    }

    public Double getPm10() {
        return pm10;
    }

    public void setPm10(Double pm10) {
        this.pm10 = pm10;
    }

    public Double getO3Concentration() {
        return o3Concentration;
    }

    public void setO3Concentration(Double o3Concentration) {
        this.o3Concentration = o3Concentration;
    }

    public Double getCoConcentration() {
        return coConcentration;
    }

    public void setCoConcentration(Double coConcentration) {
        this.coConcentration = coConcentration;
    }

    public Double getSo2Concentration() {
        return so2Concentration;
    }

    public void setSo2Concentration(Double so2Concentration) {
        this.so2Concentration = so2Concentration;
    }

    public Double getNo2Concentration() {
        return no2Concentration;
    }

    public void setNo2Concentration(Double no2Concentration) {
        this.no2Concentration = no2Concentration;
    }

    public Double getVisibility() {
        return visibility;
    }

    public void setVisibility(Double visibility) {
        this.visibility = visibility;
    }

    public Double getIllumination() {
        return illumination;
    }

    public void setIllumination(Double illumination) {
        this.illumination = illumination;
    }

    public Double getTotalRadiationIntensity() {
        return totalRadiationIntensity;
    }

    public void setTotalRadiationIntensity(Double totalRadiationIntensity) {
        this.totalRadiationIntensity = totalRadiationIntensity;
    }

    public Double getUvRadiationIntensity() {
        return uvRadiationIntensity;
    }

    public void setUvRadiationIntensity(Double uvRadiationIntensity) {
        this.uvRadiationIntensity = uvRadiationIntensity;
    }

    public Double getRainfall() {
        return rainfall;
    }

    public void setRainfall(Double rainfall) {
        this.rainfall = rainfall;
    }

    public Double getCumulativeRainfall() {
        return cumulativeRainfall;
    }

    public void setCumulativeRainfall(Double cumulativeRainfall) {
        this.cumulativeRainfall = cumulativeRainfall;
    }

    public Double getWindSpeed() {
        return windSpeed;
    }

    public void setWindSpeed(Double windSpeed) {
        this.windSpeed = windSpeed;
    }

    public Double getAccurateWindDirection() {
        return accurateWindDirection;
    }

    public void setAccurateWindDirection(Double accurateWindDirection) {
        this.accurateWindDirection = accurateWindDirection;
    }

    public WindDirection getWindDirection() {
        return windDirection;
    }

    public void setWindDirection(WindDirection windDirection) {
        this.windDirection = windDirection;
    }

    public DisasterStatus getTyphoonStatus() {
        return typhoonStatus;
    }

    public void setTyphoonStatus(DisasterStatus typhoonStatus) {
        this.typhoonStatus = typhoonStatus;
    }

    public DisasterStatus getTornadoStatus() {
        return tornadoStatus;
    }

    public void setTornadoStatus(DisasterStatus tornadoStatus) {
        this.tornadoStatus = tornadoStatus;
    }

    public DisasterStatus getLightningStatus() {
        return lightningStatus;
    }

    public void setLightningStatus(DisasterStatus lightningStatus) {
        this.lightningStatus = lightningStatus;
    }

    public DisasterStatus getHailStatus() {
        return hailStatus;
    }

    public void setHailStatus(DisasterStatus hailStatus) {
        this.hailStatus = hailStatus;
    }

    public String getRoadName() {
        return roadName;
    }

    public void setRoadName(String roadName) {
        this.roadName = roadName;
    }

    public Integer getSpeedLimit() {
        return speedLimit;
    }

    public void setSpeedLimit(Integer speedLimit) {
        this.speedLimit = speedLimit;
    }

    public RoadType getRoadType() {
        return roadType;
    }

    public void setRoadType(RoadType roadType) {
        this.roadType = roadType;
    }

    public RoadSurfaceStatus getRoadSurfaceStatus() {
        return roadSurfaceStatus;
    }

    public void setRoadSurfaceStatus(RoadSurfaceStatus roadSurfaceStatus) {
        this.roadSurfaceStatus = roadSurfaceStatus;
    }

    public TrafficStatus getRoadTraffic() {
        return roadTraffic;
    }

    public void setRoadTraffic(TrafficStatus roadTraffic) {
        this.roadTraffic = roadTraffic;
    }

    public TrafficStatus getCurrentLaneTraffic() {
        return currentLaneTraffic;
    }

    public void setCurrentLaneTraffic(TrafficStatus currentLaneTraffic) {
        this.currentLaneTraffic = currentLaneTraffic;
    }

    public TrafficStatus getLeftLaneTraffic() {
        return leftLaneTraffic;
    }

    public void setLeftLaneTraffic(TrafficStatus leftLaneTraffic) {
        this.leftLaneTraffic = leftLaneTraffic;
    }

    public TrafficStatus getRightLaneTraffic() {
        return rightLaneTraffic;
    }

    public void setRightLaneTraffic(TrafficStatus rightLaneTraffic) {
        this.rightLaneTraffic = rightLaneTraffic;
    }

    public List<Spot> getSpots() {
        return spots;
    }

    public void setSpots(List<Spot> spots) {
        this.spots = spots;
    }

    /**
     * 将环境样本转换为通用样本
     */
    public GeneralSample toGeneralSample() {
        GeneralSample sample = new GeneralSample();
        sample.setTime(this);
        sample.setProtocol(TARGET_PROTOCOL);
        
        int spotCount = spots == null ? 0 : spots.size();

        GeneralElement[] data = new GeneralElement[64 + 2 * spotCount];
        
        // 初始化数组
        for (int i = 0; i < data.length; i++) {
            data[i] = new GeneralElement();
        }

        data[1] = new GeneralElement((double)spotCount);
        data[2] = new GeneralElement((double)weatherType.getValue());
        if (temperature != null) data[3] = new GeneralElement(temperature);
        if (pm25 != null) data[4] = new GeneralElement(pm25);
        if (speedLimit != null) data[5] = new GeneralElement((double)speedLimit);
        data[6] = new GeneralElement((double)roadType.getValue());
        if (illumination != null) data[7] = new GeneralElement(illumination);
        if (windSpeed != null) data[8] = new GeneralElement(windSpeed);
        data[9] = new GeneralElement((double)roadTraffic.getValue());
        if (roadName != null) data[10] = new GeneralElement(roadName);
        if (pressure != null) data[11] = new GeneralElement(pressure);
        if (humidity != null) data[12] = new GeneralElement(humidity);
        if (visibility != null) data[13] = new GeneralElement(visibility);
        data[14] = new GeneralElement((double)windDirection.getValue());
        if (pm10 != null) data[15] = new GeneralElement(pm10);
        data[16] = new GeneralElement((double)roadSurfaceStatus.getValue());
        data[17] = new GeneralElement((double)currentLaneTraffic.getValue());
        data[18] = new GeneralElement((double)leftLaneTraffic.getValue());
        data[19] = new GeneralElement((double)rightLaneTraffic.getValue());
        data[20] = new GeneralElement((double)typhoonStatus.getValue());
        data[21] = new GeneralElement((double)tornadoStatus.getValue());
        data[22] = new GeneralElement((double)lightningStatus.getValue());
        data[23] = new GeneralElement((double)hailStatus.getValue());
        if (rainfall != null) data[24] = new GeneralElement(rainfall);
        if (cumulativeRainfall != null) data[25] = new GeneralElement(cumulativeRainfall);
        if (accurateWindDirection != null) data[26] = new GeneralElement(accurateWindDirection);
        if (totalRadiationIntensity != null) data[27] = new GeneralElement(totalRadiationIntensity);
        if (uvRadiationIntensity != null) data[28] = new GeneralElement(uvRadiationIntensity);
        if (o3Concentration != null) data[29] = new GeneralElement(o3Concentration);
        if (coConcentration != null) data[30] = new GeneralElement(coConcentration);
        if (so2Concentration != null) data[31] = new GeneralElement(so2Concentration);
        if (no2Concentration != null) data[32] = new GeneralElement(no2Concentration);
        
        // 添加场所信息
        if (spots != null) {
            for (int i = 0; i < spotCount; i++) {
                Spot spot = spots.get(i);
                data[64 + 2 * i] = new GeneralElement((double)spot.getType().getValue());
                data[64 + 2 * i + 1] = new GeneralElement(spot.getDistance());
            }
        }
        
        // 将数组转换为列表
        List<GeneralElement> elements = new ArrayList<>();
        for (GeneralElement element : data) {
            elements.add(element);
        }
        
        sample.setValues(elements.toArray(new GeneralElement[0]));
        sample.setNumberOfSignificants(data.length);
        
        return sample;
    }
    
    /**
     * 获取通用样本协议
     */
    @Override
    public String getGeneralSampleProtocol() {
        return TARGET_PROTOCOL;
    }
    
    /**
     * 获取通用样本协议列表
     */
    @Override
    public String[] getGeneralSampleProtocols() {
        return PROTOCOLS;
    }
    
    /**
     * 从通用样本转换为环境样本
     */
    @Override
    public boolean fromGeneralSample(GeneralSample sample) {
        setTime(sample);
        
        String protocol = sample.getProtocol();
        if ("env-sample-v1".equals(protocol)) {
            return fromEnvSampleV1(sample);
        } else if ("env-sample-v2".equals(protocol)) {
            return fromEnvSampleV2(sample);
        } else if ("env-sample-v3".equals(protocol)) {
            return fromEnvSampleV3(sample);
        }
        
        return false;
    }
    
    /**
     * 从EnvSampleV1通用样本转换
     */
    private boolean fromEnvSampleV1(GeneralSample sample) {
        GeneralElement[] values = sample.getValues();
        if (values.length < 1) return false;
        
        int roadNameSize = (int)values[0].getValue();
        if (values.length != 13 + roadNameSize) return false;
        
        this.weatherType = values[1].isValid() ? WeatherType.fromValue((int)values[1].getValue()) : WeatherType.UNKNOWN;
        this.temperature = getDoubleOrNull(values[2]);
        this.pm25 = getDoubleOrNull(values[3]);
        this.speedLimit = values[4].isValid() ? (int)values[4].getValue() : null;
        this.roadType = values[5].isValid() ? RoadType.fromValue((int)values[5].getValue()) : RoadType.UNKNOWN;
        this.illumination = getDoubleOrNull(values[6]);
        this.windSpeed = getDoubleOrNull(values[7]);
        this.roadTraffic = values[12].isValid() ? TrafficStatus.fromValue((int)values[12].getValue()) : TrafficStatus.UNKNOWN;
        
        // 处理道路名称
        if (roadNameSize > 0) {
            byte[] roadNameBytes = new byte[roadNameSize];
            for (int i = 0; i < roadNameSize; i++) {
                roadNameBytes[i] = (byte)((int)values[13 + i].getValue());
            }
            this.roadName = new String(roadNameBytes);
        } else {
            this.roadName = "";
        }
        
        return true;
    }
    
    /**
     * 从EnvSampleV2通用样本转换
     */
    private boolean fromEnvSampleV2(GeneralSample sample) {
        GeneralElement[] values = sample.getValues();
        if (values.length < 2) return false;
        
        int roadNameSize = (int)values[0].getValue();
        int spotCount = (int)values[1].getValue();
        
        if (values.length != 10 + 2 * spotCount + roadNameSize) return false;
        
        this.weatherType = values[2].isValid() ? WeatherType.fromValue((int)values[2].getValue()) : WeatherType.UNKNOWN;
        this.temperature = getDoubleOrNull(values[3]);
        this.pm25 = getDoubleOrNull(values[4]);
        this.speedLimit = values[5].isValid() ? (int)values[5].getValue() : null;
        this.roadType = values[6].isValid() ? RoadType.fromValue((int)values[6].getValue()) : RoadType.UNKNOWN;
        this.illumination = getDoubleOrNull(values[7]);
        this.windSpeed = getDoubleOrNull(values[8]);
        this.roadTraffic = values[9].isValid() ? TrafficStatus.fromValue((int)values[9].getValue()) : TrafficStatus.UNKNOWN;
        
        // 处理场所信息
        this.spots = new ArrayList<>();
        for (int i = 0; i < spotCount; i++) {
            if (values[10 + 2 * i].isValid() && values[10 + 2 * i + 1].isValid()) {
                Spot spot = new Spot();
                spot.setType(SpotType.fromValue((int)values[10 + 2 * i].getValue()));
                spot.setDistance(values[10 + 2 * i + 1].getValue());
                this.spots.add(spot);
            }
        }
        
        // 处理道路名称
        if (roadNameSize > 0) {
            byte[] roadNameBytes = new byte[roadNameSize];
            for (int i = 0; i < roadNameSize; i++) {
                roadNameBytes[i] = (byte)((int)values[10 + 2 * spotCount + i].getValue());
            }
            this.roadName = new String(roadNameBytes);
        } else {
            this.roadName = "";
        }
        
        return true;
    }
    
    /**
     * 从EnvSampleV3通用样本转换
     */
    private boolean fromEnvSampleV3(GeneralSample sample) {
        GeneralElement[] values = sample.getValues();
        if (values.length < 2) return false;
        
        int roadNameSize = (int)values[0].getValue();
        int spotCount = (int)values[1].getValue();
        
        if (values.length != 64 + 2 * spotCount + roadNameSize) return false;
        
        this.weatherType = values[2].isValid() ? WeatherType.fromValue((int)values[2].getValue()) : WeatherType.UNKNOWN;
        this.temperature = getDoubleOrNull(values[3]);
        this.pm25 = getDoubleOrNull(values[4]);
        this.speedLimit = values[5].isValid() ? (int)values[5].getValue() : null;
        this.roadType = values[6].isValid() ? RoadType.fromValue((int)values[6].getValue()) : RoadType.UNKNOWN;
        this.illumination = getDoubleOrNull(values[7]);
        this.windSpeed = getDoubleOrNull(values[8]);
        this.roadTraffic = values[9].isValid() ? TrafficStatus.fromValue((int)values[9].getValue()) : TrafficStatus.UNKNOWN;
        this.pressure = getDoubleOrNull(values[11]);
        this.humidity = getDoubleOrNull(values[12]);
        this.visibility = getDoubleOrNull(values[13]);
        this.windDirection = values[14].isValid() ? WindDirection.fromValue((int)values[14].getValue()) : WindDirection.UNKNOWN;
        this.pm10 = getDoubleOrNull(values[15]);
        this.roadSurfaceStatus = values[16].isValid() ? RoadSurfaceStatus.fromValue((int)values[16].getValue()) : RoadSurfaceStatus.UNKNOWN;
        this.currentLaneTraffic = values[17].isValid() ? TrafficStatus.fromValue((int)values[17].getValue()) : TrafficStatus.UNKNOWN;
        this.leftLaneTraffic = values[18].isValid() ? TrafficStatus.fromValue((int)values[18].getValue()) : TrafficStatus.UNKNOWN;
        this.rightLaneTraffic = values[19].isValid() ? TrafficStatus.fromValue((int)values[19].getValue()) : TrafficStatus.UNKNOWN;
        this.typhoonStatus = values[20].isValid() ? DisasterStatus.fromValue((int)values[20].getValue()) : DisasterStatus.UNKNOWN;
        this.tornadoStatus = values[21].isValid() ? DisasterStatus.fromValue((int)values[21].getValue()) : DisasterStatus.UNKNOWN;
        this.lightningStatus = values[22].isValid() ? DisasterStatus.fromValue((int)values[22].getValue()) : DisasterStatus.UNKNOWN;
        this.hailStatus = values[23].isValid() ? DisasterStatus.fromValue((int)values[23].getValue()) : DisasterStatus.UNKNOWN;
        this.rainfall = getDoubleOrNull(values[24]);
        this.cumulativeRainfall = getDoubleOrNull(values[25]);
        this.accurateWindDirection = getDoubleOrNull(values[26]);
        this.totalRadiationIntensity = getDoubleOrNull(values[27]);
        this.uvRadiationIntensity = getDoubleOrNull(values[28]);
        this.o3Concentration = getDoubleOrNull(values[29]);
        this.coConcentration = getDoubleOrNull(values[30]);
        this.so2Concentration = getDoubleOrNull(values[31]);
        this.no2Concentration = getDoubleOrNull(values[32]);
        
        // 处理场所信息
        this.spots = new ArrayList<>();
        for (int i = 0; i < spotCount; i++) {
            if (values[64 + 2 * i].isValid() && values[64 + 2 * i + 1].isValid()) {
                Spot spot = new Spot();
                spot.setType(SpotType.fromValue((int)values[64 + 2 * i].getValue()));
                spot.setDistance(values[64 + 2 * i + 1].getValue());
                this.spots.add(spot);
            }
        }
        
        // 处理道路名称
        if (values[10].isText()) {
            this.roadName = values[10].getText();
        } else if (roadNameSize > 0) {
            byte[] roadNameBytes = new byte[roadNameSize];
            for (int i = 0; i < roadNameSize; i++) {
                roadNameBytes[i] = (byte)((int)values[64 + 2 * spotCount + i].getValue());
            }
            this.roadName = new String(roadNameBytes);
        } else {
            this.roadName = "";
        }
        
        return true;
    }
    
    /**
     * 是否支持插值
     */
    @Override
    public boolean supportInterpolation() {
        return true;
    }
    
    /**
     * 插值生成中间样本
     */
    @Override
    public Sample interpolate(SearchResult result) {
        EnvSample s1 = (EnvSample) result.getS1();
        EnvSample s2 = (EnvSample) result.getS2();
        double w1 = result.getW1();
        double w2 = result.getW2();
        
        EnvSample output = new EnvSample();
        
        // 使用权重较大的一方的枚举类型值
        output.weatherType = w1 > w2 ? s1.weatherType : s2.weatherType;
        output.windDirection = w1 > w2 ? s1.windDirection : s2.windDirection;
        output.roadType = w1 > w2 ? s1.roadType : s2.roadType;
        output.roadSurfaceStatus = w1 > w2 ? s1.roadSurfaceStatus : s2.roadSurfaceStatus;
        output.roadTraffic = w1 > w2 ? s1.roadTraffic : s2.roadTraffic;
        output.currentLaneTraffic = w1 > w2 ? s1.currentLaneTraffic : s2.currentLaneTraffic;
        output.leftLaneTraffic = w1 > w2 ? s1.leftLaneTraffic : s2.leftLaneTraffic;
        output.rightLaneTraffic = w1 > w2 ? s1.rightLaneTraffic : s2.rightLaneTraffic;
        output.typhoonStatus = w1 > w2 ? s1.typhoonStatus : s2.typhoonStatus;
        output.tornadoStatus = w1 > w2 ? s1.tornadoStatus : s2.tornadoStatus;
        output.lightningStatus = w1 > w2 ? s1.lightningStatus : s2.lightningStatus;
        output.hailStatus = w1 > w2 ? s1.hailStatus : s2.hailStatus;
        
        // 使用权重平均的数值型参数
        output.temperature = interpolateDouble(s1.temperature, s2.temperature, w1, w2);
        output.humidity = interpolateDouble(s1.humidity, s2.humidity, w1, w2);
        output.pressure = interpolateDouble(s1.pressure, s2.pressure, w1, w2);
        output.pm25 = interpolateDouble(s1.pm25, s2.pm25, w1, w2);
        output.pm10 = interpolateDouble(s1.pm10, s2.pm10, w1, w2);
        output.o3Concentration = interpolateDouble(s1.o3Concentration, s2.o3Concentration, w1, w2);
        output.coConcentration = interpolateDouble(s1.coConcentration, s2.coConcentration, w1, w2);
        output.so2Concentration = interpolateDouble(s1.so2Concentration, s2.so2Concentration, w1, w2);
        output.no2Concentration = interpolateDouble(s1.no2Concentration, s2.no2Concentration, w1, w2);
        output.visibility = interpolateDouble(s1.visibility, s2.visibility, w1, w2);
        output.illumination = interpolateDouble(s1.illumination, s2.illumination, w1, w2);
        output.totalRadiationIntensity = interpolateDouble(s1.totalRadiationIntensity, s2.totalRadiationIntensity, w1, w2);
        output.uvRadiationIntensity = interpolateDouble(s1.uvRadiationIntensity, s2.uvRadiationIntensity, w1, w2);
        output.rainfall = interpolateDouble(s1.rainfall, s2.rainfall, w1, w2);
        output.cumulativeRainfall = interpolateDouble(s1.cumulativeRainfall, s2.cumulativeRainfall, w1, w2);
        output.windSpeed = interpolateDouble(s1.windSpeed, s2.windSpeed, w1, w2);
        output.accurateWindDirection = interpolateDouble(s1.accurateWindDirection, s2.accurateWindDirection, w1, w2);
        
        // 非数值类型数据使用权重较大一方的值
        output.roadName = w1 > w2 ? s1.roadName : s2.roadName;
        output.speedLimit = w1 > w2 ? s1.speedLimit : s2.speedLimit;
        output.spots = w1 > w2 ? s1.spots : s2.spots;
        
        return output;
    }
    
    /**
     * 插值Double类型数据，处理null情况
     */
    private Double interpolateDouble(Double v1, Double v2, double w1, double w2) {
        if (v1 == null && v2 == null) return null;
        if (v1 == null) return v2;
        if (v2 == null) return v1;
        return v1 * w1 + v2 * w2;
    }
    
    /**
     * 从GeneralElement获取Double或null
     */
    private Double getDoubleOrNull(GeneralElement element) {
        return element != null && element.isValid() ? element.getValue() : null;
    }

    // 协议相关常量
    public static final String TARGET_PROTOCOL = "env-sample-v3";
    public static final String[] PROTOCOLS = {
        "env-sample-v1", "env-sample-v2", "env-sample-v3"
    };
} 